﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BadHabit.Factory.Data {


    /// <summary>
    /// Implements the business functions for project dataset.
    /// 
    /// Some of the methods here uses the concept of a VISIBLE BACKLOG and VISIBLE BACKLOG ITEM.
    /// 
    /// A VISIBLE BACKLOG is a no typed dataset where all backlogitems are converted to VISIBLE BACKLOG ITEMs.
    /// 
    /// A VISIBLE BACKLOG ITEM is a backlog item added of some new columns:
    ///   - SprintUId
    ///   - SprintNumber
    ///   - BaseLine
    ///   - and one colllumn per backlog unit with its planned hours.
    /// 
    /// </summary>
    public partial class  ProjectDataSet {

               

        /// <summary>
        /// Keeps tracking whenever is reflecting a Visible BacklogItem Column change 
        /// at the Backlogitem datatable or not.
        /// </summary>
        private bool isReflectingVisibleChanges = false;


        /// <summary>
        /// Define the number of days ripping of the saturdays and sundays.
        /// </summary>
        /// <returns>The number of work days</returns>
        public static int CalcWorkDayCount(DateTime start, DateTime end) {
            DateTime day = start.Date;
            int dayCount = 0;
            while (day <= end.Date) {
                if (IsWorkDay(day))
                    dayCount++;
                day = day.AddDays(1);
            }
            return dayCount;

        }

        /// <summary>
        /// Normal human beings do not work on weekends.
        /// Verify if the day is a work day.
        /// </summary>
        /// <param name="day"></param>
        /// <returns>True if the day is not a weekend</returns>
        public static bool IsWorkDay(DateTime day) {
            return (!DayOfWeek.Saturday.Equals(day.DayOfWeek) &&
                    !DayOfWeek.Sunday.Equals(day.DayOfWeek));
        }


        /// <summary>
        /// Gets the Visible Backlog Item table.
        /// </summary>
        public System.Data.DataTable VisibleBacklogItem {
            get {
                if (!Tables.Contains("VisibleBacklogItem"))
                    throw new Exception("ProjectDataSet should be converted first to a Visible Backlog in order to access a VisibleBacklogItem table.");
                return Tables["VisibleBacklogItem"];
            }
        }

        /// <summary>
        /// Gets the name of the unit column from a given unitName at the visible backlog item.
        /// </summary>
        /// <param name="unitName"></param>
        /// <returns></returns>
        public string GetVisibleUnitColumnName(string unitName) {
            return "unit" + unitName.Replace(" ", "").Replace(".", "").ToUpper();

        }


        public bool IsConvertedToVisibleBacklog {
            get {
                return Tables.Contains("VisibleBacklogItem");
            }
            
        }

        /// <summary>
        /// Converts this dataset into a Visible backlog.        
        /// </summary>        
        public void ConvertToVisibleBacklog() {

            
            // adds the visible backlog item table
            AddVisibleBacklogItemTable();                                  

            // adds sprint extra columns
            if(!Sprint.Columns.Contains("IsCurrentSprint"))
                Sprint.Columns.Add("IsCurrentSprint", typeof(bool));

            if (!Sprint.Columns.Contains("TotalSize"))
                Sprint.Columns.Add("TotalSize", typeof(long));
            
            if (!Sprint.Columns.Contains("TotalHours"))
                Sprint.Columns.Add("TotalHours", typeof(double));

            if (!Sprint.Columns.Contains("PlannedVelocity"))
                Sprint.Columns.Add("PlannedVelocity", typeof(double));

            if (!Sprint.Columns.Contains("IsPlanOver"))
                Sprint.Columns.Add("IsPlanOver", typeof(bool));

            if (!Sprint.Columns.Contains("IsLastSprint"))
                Sprint.Columns.Add("IsLastSprint", typeof(bool));

            if (!Sprint.Columns.Contains("WorkDayCount"))
                Sprint.Columns.Add("WorkDayCount", typeof(int));

            if (!Sprint.Columns.Contains("WorkDayLeft"))
                Sprint.Columns.Add("WorkDayLeft", typeof(int));
            
            if (!Sprint.Columns.Contains("NumberOfMembersNeeded"))
                Sprint.Columns.Add("NumberOfMembersNeeded", typeof(double));

            if (!Sprint.Columns.Contains("CodeVersion"))
                Sprint.Columns.Add("CodeVersion", typeof(int));

            if (!Sprint.Columns.Contains("IsCurrentSprint"))
                Sprint.Columns["IsCurrentSprint"].DefaultValue = false;

            if (!Sprint.Columns.Contains("IsPlanOver"))
                Sprint.Columns["IsPlanOver"].DefaultValue = false;

            if (!Sprint.Columns.Contains("IsLastSprint"))
                Sprint.Columns["IsLastSprint"].DefaultValue = false;

            if (!Sprint.Columns.Contains("CodeVersion"))
                Sprint.Columns["CodeVersion"].DefaultValue = 0;

            // adds proposal extra columns
            if (!Proposal.Columns.Contains("CalculatedBacklogPrice"))
                Proposal.Columns.Add("CalculatedBacklogPrice", typeof(decimal));

            if (!Proposal.Columns.Contains("CalculatedBacklogCost"))
                Proposal.Columns.Add("CalculatedBacklogCost", typeof(decimal));

            if (!Proposal.Columns.Contains("CalculatedFixedCost"))
                Proposal.Columns.Add("CalculatedFixedCost", typeof(decimal));

            if (!Proposal.Columns.Contains("CalculatedTotalPrice"))
                Proposal.Columns.Add("CalculatedTotalPrice", typeof(decimal));


            // adds project extra columns           
            if (!Project.Columns.Contains("TotalHours"))
                Project.Columns.Add("TotalHours", typeof(double));

            if (!Project.Columns.Contains("PlannedVelocity"))
                Project.Columns.Add("PlannedVelocity", typeof(double));

            if (!Project.Columns.Contains("IsPlanningLate"))
                Project.Columns.Add("IsPlanningLate", typeof(bool));

            if (!Project.Columns.Contains("EndDate"))
                Project.Columns.Add("EndDate", typeof(DateTime));

            if (!Project.Columns.Contains("NextSprintNumber"))
                Project.Columns.Add("NextSprintNumber", typeof(short));

            if (!Project.Columns.Contains("NextBaseLine"))
                Project.Columns.Add("NextBaseLine", typeof(int));

            // adds backlog item hours columns
            if(!BacklogItemUnit.Columns.Contains("HoursAtProposal"))
                BacklogItemUnit.Columns.Add("HoursAtProposal", typeof(double));

            
            Project.Columns["IsPlanningLate"].DefaultValue = false;

            // now comes the harder...feel these columns
            FillVisibleBacklog();

            //this.AcceptChanges();

        }

        /// <summary>
        /// When a VisibleBacklogItem row is deleted, delete its BacklogItemHours rows.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>        
        void VisibleBacklogItem_RowDeleting(object sender, System.Data.DataRowChangeEventArgs e) {

            if ((bool)e.Row["IsPlanOver"])
                throw new Exception("You can not delete a row from a already planned sprint.");

            // finds the item
            BacklogItemRow item = BacklogItem.FindByBacklogItemUId(e.Row["BacklogItemUId"].ToString());

            // delete its backlog item hours
            BacklogItemHoursRow[] hours = item.GetBacklogItemHoursForSprint(e.Row["SprintUId"].ToString(), (int)e.Row["Baseline"]);
            for (int i = hours.Length - 1; i >= 0; i--)
                hours[i].Delete();

            // it may happen that this item ha never being re-planned,
            // so i should also delete item from the BacklogItem table
            if (item.GetBacklogItemHoursRows().Length == 0)
                item.Delete();

            // Updates total
            UpdateTotals(e.Row);
        }


        /// <summary>
        /// Cleans the VisibleBacklogLog removing the VisibleBacklogItemTable.
        /// </summary>
        public void CleanUpVisibleBacklog() {
            if (Tables.Contains("VisibleBacklogItem"))
                Tables.Remove(VisibleBacklogItem.TableName);
        }



        /// <summary>
        /// Reflects the changes made at the visible backlog columns at the backlogitem hours datatable.
        /// </summary>
        /// <param name="e"></param>
        private void ReflectVisibleBacklogSprintChange(System.Data.DataColumnChangeEventArgs e) {
            if (isReflectingVisibleChanges)
                return;

            // if is adding a new item those values may be null
            if (e.Row["Baseline"] == DBNull.Value)
                return;
            if (e.Row["SprintUId"] == DBNull.Value)
                return;
       
            isReflectingVisibleChanges = true;


            // updates the sprin number
            SprintRow sprint = Sprint.FindBySprintUId(e.ProposedValue.ToString());
            e.Row["SprintNumber"] = sprint.SprintNumber;

            // finds the item
            BacklogItemRow item = BacklogItem.FindByBacklogItemUId(e.Row["BacklogItemUId"].ToString());

            

            // updates its backlog item hours
            BacklogItemHoursRow[] hours = item.GetBacklogItemHoursForSprint(e.Row["SprintUId"].ToString(), (int)e.Row["Baseline"]);
            for (int i = hours.Length - 1; i >= 0; i--) {                
                hours[i].SprintUId = e.ProposedValue.ToString();                
            }

            isReflectingVisibleChanges = false;
        }



        /// <summary>
        /// Reflects the changes made at the visible backlog columns at the backlogitem datatable.
        /// </summary>
        /// <param name="e"></param>
        private void ReflectIsAtProposalChange(System.Data.DataColumnChangeEventArgs e) {
            if (isReflectingVisibleChanges)
                return;

            bool IsAtProposal = (bool) e.ProposedValue;

            // gets the item values
            string backlogItemUId = e.Row["BacklogItemUId"].ToString();
            string sprintUId = e.Row["SprintUId"].ToString();
            int baseline = (int)e.Row["Baseline"];

            // get item
            BacklogItemRow item = BacklogItem.FindByBacklogItemUId(backlogItemUId);
            if (item == null)
                throw new Exception("Could not update IsAtProposal, backlogitem not found.");

            // get sprint
            SprintRow sprint = Sprint.FindBySprintUId(sprintUId);
            if(sprint==null)
                throw new Exception("Could not update IsAtProposal, sprint not found.");

            if (item.ProjectRow.MarkedProposal == null)
                return;
            
            // get the proposal item
            ProposalItemRow proposalItem = ProposalItem.FindByProposalUIdBacklogItemUIdSprintUIdBaseLine(
                 item.ProjectRow.MarkedProposal.ProposalUId,
                 backlogItemUId,
                 sprintUId,
                 baseline);

            isReflectingVisibleChanges = true;
            
            // if the item is at the proposal, make sure the it has a ProposalItem row for it
            if (IsAtProposal) {
                            
                // no item...add new one
                if (proposalItem == null)
                    ProposalItem.AddProposalItemRow(
                        item.ProjectRow.MarkedProposal,
                        item,
                        sprint,
                        baseline);
            } else {
                if(proposalItem!=null)
                    proposalItem.Delete();
            }

            item.ProjectRow.MarkedProposal.UpdateCalculatedCosts();
            item.ProjectRow.MarkedProposal.UpdateSalePrice(item.ProjectRow.MarkedProposal.UseDiscount);
            

            isReflectingVisibleChanges = false;
         
        }

                       
        /// <summary>
        /// Reflects the changes made at the visible backlog columns at the backlogitem datatable.
        /// </summary>
        /// <param name="e"></param>
        private void ReflectVisibleBacklogItemChange(System.Data.DataColumnChangeEventArgs e) {
            if (isReflectingVisibleChanges)
                return;

            isReflectingVisibleChanges = true;

            // updates the Backlogitem table
            BacklogItemRow item = BacklogItem.FindByBacklogItemUId(e.Row["BacklogItemUId"].ToString());
            // so its a new row
            if (item == null) {                
                item = BacklogItem.NewBacklogItemRow();
                item.BacklogItemUId = e.Row["BacklogItemUId"].ToString();                                
            }

            item[e.Column.ColumnName] = e.ProposedValue;

            // updates the others visible backlogitems with the same UId
            System.Data.DataRow[] visibleRows = VisibleBacklogItem.Select("BacklogItemUId='" + item.BacklogItemUId + "'");
            foreach (System.Data.DataRow r in visibleRows)
                r[e.Column.ColumnName] = e.ProposedValue;

            isReflectingVisibleChanges = false;
         
        }

        internal void CalcItemCosts(string backlogItemUId, string sprintUId, int baseline, out decimal itemCost, out decimal itemPrice, out double itemHours) {
            itemCost = 0;
            itemPrice = 0;
            itemHours = 0;
            
            // finds the corresponding backlog item for the visible item
            BacklogItemRow item = BacklogItem.FindByBacklogItemUId(backlogItemUId);
            if (item == null)
                return;

            
            // for each planned hour, multiply for its cost
            foreach (BacklogItemHoursRow hours in item.GetBacklogItemHoursForSprint(sprintUId, baseline)) {
                Data.ProjectDataSet.BacklogItemUnitRow unit = BacklogItemUnit.FindByUnitNameProjectUId(hours.UnitName, hours.ProjectUId);
                itemHours = itemHours + hours.Quantity;
                if (unit != null) {
                    if(!unit.IsUnitCostValueNull())
                        itemCost = itemCost + (unit.UnitCostValue * (decimal)hours.Quantity);
                    if(!unit.IsUnitSaleValueNull())
                        itemPrice = itemPrice + (unit.UnitSaleValue * (decimal) hours.Quantity);
                }
            }

        }



        private void UpdateItemCosts(System.Data.DataRow row) {

            if (row.RowState == System.Data.DataRowState.Deleted || row.RowState == System.Data.DataRowState.Detached)
                return;

            if (isReflectingVisibleChanges)
                return;
                        
            isReflectingVisibleChanges = true;

            decimal cost;
            decimal price;
            double hours;

            CalcItemCosts(row["BacklogItemUId"].ToString(), row["SprintUId"].ToString(), (int)row["Baseline"], out cost, out price, out hours);
            row["ItemHours"] = hours;
            row["ItemCost"] = cost;
            row["ItemPrice"] = price;

            isReflectingVisibleChanges = false;

            /*
            if (!updateProposal)
                return;

            // finds the corresponding backlog item for the visible item
            BacklogItemRow item = BacklogItem.FindByBacklogItemUId(row["BacklogItemUId"].ToString());
            if (item == null)
                return;

            foreach (Data.ProjectDataSet.ProposalItemRow proposalItemRow in (Data.ProjectDataSet.ProposalItemRow[])item.GetParentRows("BacklogItem_ProposalItem")) {
                proposalItemRow.ProposalRow.UpdateCalculatedCosts();
            }*/



        }

        /// <summary>
        /// Reflects the changes made at the visible backlog unit columns at the backlogitem datatable.
        /// </summary>
        private void ReflectVisibleBacklogItemUnitChange(System.Data.DataColumnChangeEventArgs e) {

            if (isReflectingVisibleChanges)
                return;

            if (e.Row.RowState == System.Data.DataRowState.Deleted || e.Row.RowState == System.Data.DataRowState.Detached)
                return;

            if ((bool)e.Row["IsPlanOver"])
                throw new Exception("You can not change an already planned item.");

            isReflectingVisibleChanges = true;
            
            // gets the necessary info
            string unitName = e.Column.ExtendedProperties["unitName"].ToString();
            int baseline = (int)e.Row["BaseLine"];

            ProjectRow project = Project.FindByProjectUId(e.Row["ProjectUId"].ToString());
            SprintRow sprint = Sprint.FindBySprintUId(e.Row["SprintUId"].ToString());
            BacklogItemRow item = BacklogItem.FindByBacklogItemUId(e.Row["BacklogItemUId"].ToString());

            // finds the hours row
            BacklogItemHoursRow hoursRow = BacklogItemHours.FindByUniqueValues(e.Row["BacklogItemUId"].ToString(), sprint.SprintUId, unitName, baseline);

            // if is a empty value, deletes the backlogitemhour row
            if (e.ProposedValue == null || e.ProposedValue.ToString().Equals(String.Empty)) {
                if (hoursRow != null)
                    hoursRow.Delete();
                isReflectingVisibleChanges = false;
                return;
            }

            // if is a ok double, updates the backlogitemhour row
            double quantity = 0;
            if (Double.TryParse(e.ProposedValue.ToString(), out quantity)) {

                // if there is not hour row yet
                if (hoursRow == null) {

                   
                    if(BacklogItem.FindByBacklogItemUId(item.BacklogItemUId)==null)
                        BacklogItem.AddBacklogItemRow(item);

                    BacklogItemHours.AddBacklogItemHoursRow(
                        Guid.NewGuid().ToString().ToLower(),
                        item,
                        item.ProjectUId,
                        unitName,
                        quantity,
                        sprint,
                        baseline);
                } else
                    hoursRow.Quantity = quantity;
            }

            isReflectingVisibleChanges = false;
        }

        


        /// <summary>
        /// Adds a Visible Backlog Item DataTable using the same structure of the BacklogItem Table.
        /// </summary>
        /// <param name="dsVisible"></param>
        private void AddVisibleBacklogItemTable() {

            if (Tables.Contains("VisibleBacklogItem"))
                return;

            System.Data.DataTable table = BacklogItem.Clone();
            table.TableName = "VisibleBacklogItem";
            table.Constraints.Clear(); //  this table will be not normalized, so no constranints here            
            Tables.Add(table);

            // now create the new columns, first creates the unit columns at each 
            foreach (Data.ProjectDataSet.BacklogItemUnitRow unit in BacklogItemUnit.Select("Type <> " + (short)TeamRoles.CLIENT_CONTACT)) {
                System.Data.DataColumn c = VisibleBacklogItem.Columns.Add(GetVisibleUnitColumnName(unit.UnitName), typeof(double));
                //c.DefaultValue = 0;
                c.ExtendedProperties.Add("unitName", unit.UnitName);
            }

            // now the Sprint UId, Number and Baseline collumn
            VisibleBacklogItem.Columns.Add("SprintUId", typeof(string));
            VisibleBacklogItem.Columns.Add("SprintNumber", typeof(short));
            VisibleBacklogItem.Columns.Add("BaseLine", typeof(int));
            VisibleBacklogItem.Columns.Add("IsSprintOver", typeof(bool));
            VisibleBacklogItem.Columns.Add("IsPlanOver", typeof(bool));
            VisibleBacklogItem.Columns.Add("ItemHours", typeof(double));
            VisibleBacklogItem.Columns.Add("ItemCost", typeof(decimal));
            VisibleBacklogItem.Columns.Add("ItemPrice", typeof(decimal));

            VisibleBacklogItem.Columns.Add("IsVisible", typeof(bool));
            
            VisibleBacklogItem.Columns.Add("IsAtProposal", typeof(bool));

            VisibleBacklogItem.Columns["IsSprintOver"].DefaultValue = false;
            VisibleBacklogItem.Columns["IsPlanOver"].DefaultValue = false;
            VisibleBacklogItem.Columns["IsVisible"].DefaultValue = true;
            VisibleBacklogItem.Columns["IsAtProposal"].DefaultValue = false;



        
            

        }

        
        
        

        /// <summary>
        /// Loops throuth the projects in the dataset and fills it.
        /// </summary>
        /// <param name="dsVisible"></param>
        private void FillVisibleBacklog() {


            // fill the visiblebacklogitems
            foreach (ProjectRow project in Project.Rows) {

                System.Data.DataRowState oldRowState = project.RowState;

                project.FillVisibleBacklog();


                foreach (System.Data.DataRow item in VisibleBacklogItem.Rows) {
                    UpdateItemCosts(item);
                    item.AcceptChanges();
                }

                foreach (SprintRow sprint in project.GetSprintRows()) {
                    sprint.UpdateTotalSize();
                    sprint.UpdateTotalHours();
                    sprint.UpdatePlannedVelocity();
                    sprint.UpdateIsPlanOver();
                    sprint.UpdateIsLastSprint();
                    sprint.UpdateWorkDayCount();
                    sprint.UpdateWorkDayLeft();
                    sprint.UpdateNumberOfMembersNeeded();
                    sprint.UpdateCodeRevision();
                    if(sprint.RowState!=System.Data.DataRowState.Added)
                        sprint.AcceptChanges();
                }

                
                foreach(ProposalRow proposal in project.GetProposalRows()) {
                    proposal.UpdateCalculatedCosts();
                    if (proposal.RowState != System.Data.DataRowState.Added)
                        proposal.AcceptChanges();                    
                }


                project.UpdateTotalSize();
                project.UpdateTotalHours();
                project.UpdatePlannedVelocity();
                project.UpdateIsPlanningLate();
                
                // if is not a new project
                if (System.Data.DataRowState.Unchanged.Equals(oldRowState)) {
                    project.AcceptChanges();
                    foreach (Data.ProjectDataSet.BacklogItemUnitRow unit in project.GetBacklogItemUnitRows())
                        unit.AcceptChanges();
                }
            }


            VisibleBacklogItem.ColumnChanging += new System.Data.DataColumnChangeEventHandler(VisibleBacklogItem_ColumnChanging);
            VisibleBacklogItem.ColumnChanged += new System.Data.DataColumnChangeEventHandler(VisibleBacklogItem_ColumnChanged);
            VisibleBacklogItem.RowDeleting += new System.Data.DataRowChangeEventHandler(VisibleBacklogItem_RowDeleting);
            

            Sprint.RowDeleted += new System.Data.DataRowChangeEventHandler(Sprint_RowDeleted);
            Sprint.TableNewRow += new System.Data.DataTableNewRowEventHandler(Sprint_TableNewRow);

            Sprint.ColumnChanged += new System.Data.DataColumnChangeEventHandler(Sprint_ColumnChanged);

            Project.ColumnChanged += new System.Data.DataColumnChangeEventHandler(Project_ColumnChanged);

            Proposal.ColumnChanging += new System.Data.DataColumnChangeEventHandler(Proposal_ColumnChanging);

            ProposalFixedCostItem.ColumnChanged += new System.Data.DataColumnChangeEventHandler(ProposalFixedCostItem_ColumnChanged);
            
           

        }

        void ProposalFixedCostItem_ColumnChanged(object sender, System.Data.DataColumnChangeEventArgs e) {
            
            Data.ProjectDataSet.ProposalFixedCostItemRow costItem = e.Row as Data.ProjectDataSet.ProposalFixedCostItemRow;
            if (costItem == null)
                return;

            if (costItem.ProposalRow != null) {
                costItem.ProposalRow.UpdateCalculatedCosts();
                costItem.ProposalRow.UpdateSalePrice();
            }

        }

       

        void Proposal_ColumnChanging(object sender, System.Data.DataColumnChangeEventArgs e) {

            Data.ProjectDataSet.ProposalRow proposal = e.Row as Data.ProjectDataSet.ProposalRow;
            if (proposal == null)
                return;

            if (e.Column.Equals(Proposal.DiscountColumn)) {
                proposal.UpdateCalculatedTotalPrice((decimal)e.ProposedValue);
                proposal.UpdateSalePrice(proposal.UseDiscount);
            }

            if (e.Column.Equals(Proposal.UseDiscountColumn))                
                proposal.UpdateSalePrice((bool)e.ProposedValue);

                            
            
        }

        void Project_ColumnChanged(object sender, System.Data.DataColumnChangeEventArgs e) {
            if (e.Column==Project.EstimatedStartDateColumn) {
                Data.ProjectDataSet.ProjectRow project = e.Row as Data.ProjectDataSet.ProjectRow;
                if (project != null) {
                    project.ValidadeEstimatedStartDate(e);
                    project.UpdateIsPlanningLate();
                }
            }
        }

        void Sprint_ColumnChanged(object sender, System.Data.DataColumnChangeEventArgs e) {
            if (e.Column==Sprint.ExpirationDateColumn) {
                Data.ProjectDataSet.SprintRow sprint = e.Row as Data.ProjectDataSet.SprintRow;
                if (sprint != null)
                    sprint.ValidadeExpirationDate(e);
            }
        }



        void Sprint_TableNewRow(object sender, System.Data.DataTableNewRowEventArgs e) {
            foreach (SprintRow sprint in Sprint) {
                sprint.UpdateIsLastSprint();
                sprint.UpdateIsCurrentSprint();
            }
        }

        void Sprint_RowDeleted(object sender, System.Data.DataRowChangeEventArgs e) {
            foreach (SprintRow sprint in Sprint) {
                sprint.UpdateIsLastSprint();
                sprint.UpdateIsCurrentSprint();
            }
        }

    

        /// <summary>
        /// Every time that the Visible BacklogItem has changed, updates the sprint totals and project totals.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void VisibleBacklogItem_ColumnChanged(object sender, System.Data.DataColumnChangeEventArgs e) {
            UpdateTotals(e.Row);
        }

        private void UpdateTotals(System.Data.DataRow row) {

            // update row costs
            UpdateItemCosts(row);

            

            // update sprint information
            SprintRow sprint = Sprint.FindBySprintUId(row["SprintUId"].ToString());
            if (sprint != null) {
                sprint.UpdateTotalSize();
                sprint.UpdateTotalHours();
                sprint.UpdatePlannedVelocity();
                sprint.UpdateWorkDayCount();
                sprint.UpdateWorkDayLeft();
                sprint.UpdateNumberOfMembersNeeded();                
            }

            // update project information
            ProjectRow project = Project.FindByProjectUId(row["ProjectUId"].ToString());
            if (project != null) {
                project.UpdateTotalSize();
                project.UpdateTotalHours();
                project.UpdatePlannedVelocity();                
            }
        }

        /// <summary>
        /// Every time that the Visible BacklogItem is changing, reflects its real table Backlogitem and BacklogItemHours.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void VisibleBacklogItem_ColumnChanging(object sender, System.Data.DataColumnChangeEventArgs e) {
            
            // if its the sprint uid
            if (e.Column.ColumnName.Equals("SprintUId")) 
                ReflectVisibleBacklogSprintChange(e);
            
            // so it is a unit column that has changed
            if (e.Column.ColumnName.StartsWith("unit")) 
                ReflectVisibleBacklogItemUnitChange(e);

            // if its a backlogitem column                        
            if (BacklogItem.Columns.Contains(e.Column.ColumnName))
                ReflectVisibleBacklogItemChange(e);

            // if is the AtProposal Marker
            if (e.Column.ColumnName.Equals("IsAtProposal"))
                ReflectIsAtProposalChange(e);

        }

        
        /// <summary>
        /// Business functions for a project row.
        /// </summary>
        public partial class ProjectRow {
     
            /// <summary>
            /// Gets the ProjectDataSet of this project row.
            /// </summary>
            internal Data.ProjectDataSet ProjectDataSet {
                get {
                    Data.ProjectDataSet dsProject = this.Table.DataSet as Data.ProjectDataSet;
                    if (dsProject == null)
                        throw new Exception("Could not find project dataset from the row.");
                    return dsProject;
                }
            }

            public void BreakLastSprintByHour(double maxHours, int sprintLength, Data.ProjectDataSet dsSprintDefaultItems) {
                                
                // if there is no last sprint return                
                if (LastSprint == null)
                    return;

                if (!System.DBNull.Value.Equals(LastSprint["IsPlanOver"]) && (bool)LastSprint["IsPlanOver"])
                    return;
                

                Data.ProjectDataSet.SprintRow oldLastSprint = LastSprint;
                Data.ProjectDataSet.SprintRow newLastSprint = null;

                double defaultItemsHours = 0;
                if (dsSprintDefaultItems != null) {
                    object o = dsSprintDefaultItems.BacklogItemHours.Compute("SUM(Quantity)","");
                    if (!double.TryParse(o.ToString(), out defaultItemsHours))
                        defaultItemsHours = 0;
                }

                double sprintHours = 0;
                System.Data.DataRow[] rows = ProjectDataSet.VisibleBacklogItem.Select("IsVisible=1 and IsPlanOver=0 and SprintUId='" + LastSprint.SprintUId + "'", "BusinessValue DESC");                
                int itemIndex = 0;
                foreach (System.Data.DataRow item in rows) {

                    // the item hours
                    double itemHours = 0;
                    if (!DBNull.Value.Equals(item["ItemHours"]))
                        itemHours = (double)item["ItemHours"];

                    // sum item hours to the sprint hours
                    sprintHours = sprintHours + itemHours;

                    // if there is now new sprint
                    if (newLastSprint == null) {
                        // if it does not fit at the last sprint, creat a new one
                        if (sprintHours > maxHours - defaultItemsHours ) {                            
                            newLastSprint = AddNewSprint();                            
                            newLastSprint.ExpirationDate = oldLastSprint.ExpirationDate.AddDays(sprintLength);
                        }
                    }

                    // if there is a new last sprint, move the item to it
                    if (newLastSprint != null) {
                        if (itemIndex != 0)                            
                            item["SprintUId"] = newLastSprint.SprintUId;                        
                    }

                    itemIndex++;

                }

                if (dsSprintDefaultItems != null)
                    AddItemsToSprint(dsSprintDefaultItems, oldLastSprint);

                oldLastSprint.UpdateIsLastSprint();
                oldLastSprint.UpdateIsCurrentSprint();
                oldLastSprint.UpdateTotalHours();
                oldLastSprint.UpdateTotalSize();
                oldLastSprint.UpdatePlannedVelocity();
                
                // if a news sprint was added, do it again
                if (newLastSprint != null) 
                    BreakLastSprintByHour(maxHours, sprintLength, dsSprintDefaultItems);                    
                

            }


            internal void ValidadeEstimatedStartDate(System.Data.DataColumnChangeEventArgs e) {

                DateTime newDate = (DateTime)e.ProposedValue;

                if (newDate > FirstSprint.ExpirationDate)
                    throw new Exception("Project Start Date can not be after the first sprint Expiration date.");
               

            }

            public void AcceptPlannedItems() {
                Data.ProjectDataSet.SprintRow baseLineSprint = FindSprintByNumber((short)Baseline);
                if (baseLineSprint == null)
                    return;
                foreach (Data.ProjectDataSet.BacklogItemRow item in ProjectDataSet.BacklogItem.Select("ProjectUId='" + ProjectUId + "' AND Status <>" + (short)BacklogItemStatus.CANCELED)) {
                    // if there are hours planned for this item at the planned sprint, at the current sprint and it has never been accpted, do so
                    if (item.GetBacklogItemHoursForSprint(baseLineSprint.SprintUId).Length > 0 && item.IsAcceptedDateNull()) {
                        if(!item.IsSizeItemTypeNull())
                            item.AcceptedDate = DateTime.Now;
                    }
                }
            }

            public void FinishItemsToClose() {
                foreach (Data.ProjectDataSet.BacklogItemRow item in ProjectDataSet.BacklogItem.Select("ProjectUId='" + ProjectUId + "' AND Status <2"))
                    item.Status = (short) BacklogItemStatus.DONE;
            }

            public bool IsThereAnyUnfinishItem {
                get {
                    return (ProjectDataSet.BacklogItem.Select("ProjectUId='" + ProjectUId + "' AND Status <2").Length > 0);
                }
            }

            

            public Data.ProjectDataSet.SprintRow AddNewSprint() {
                return AddNewSprint(null);
            }

            public Data.ProjectDataSet.SprintRow AddNewSprint(ProjectDataSet dsSprintDefaultItems) {

               
                DateTime expirationDate = DateTime.Now.AddDays(15);
                if (LastSprint != null) {                    
                    expirationDate = LastSprint.ExpirationDate.AddDays(15);
                }

                // adds the sprint
                short sprintNumber = NextSprintNumber;
                Data.ProjectDataSet.SprintRow sprint = ProjectDataSet.Sprint.NewSprintRow();
                sprint.SprintUId = Guid.NewGuid().ToString().ToLower();
                sprint.ProjectRow = this;
                sprint.SprintNumber = sprintNumber;
                sprint.Title = "Sprint " + sprintNumber;
                sprint.CreateDate = DateTime.Now;
                sprint.ExpirationDate = expirationDate;
                ProjectDataSet.Sprint.AddSprintRow(sprint);

                // if has default items, add them
                if (dsSprintDefaultItems != null)
                    AddItemsToSprint(dsSprintDefaultItems, sprint);

                if(ProjectDataSet.IsConvertedToVisibleBacklog)
                    this["NextSprintNumber"] = NextSprintNumber;

                foreach (Data.ProjectDataSet.SprintRow sp in ProjectDataSet.Sprint)
                    sp.UpdateIsLastSprint();
                                
                sprint.UpdateIsCurrentSprint();
                sprint.UpdateTotalHours();
                sprint.UpdateTotalSize();
                sprint.UpdatePlannedVelocity();

                

                return sprint;

            }
            private int GetPreviousSprintLowestBusinessValue(Data.ProjectDataSet.SprintRow sprint) {

                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return 1000;

                if (sprint.SprintNumber == 1)
                    return 1000;
                object o = ProjectDataSet.VisibleBacklogItem.Compute("MIN(BusinessValue)", "SprintNumber=" + (short)(sprint.SprintNumber - 1)); 
                if(DBNull.Value.Equals(o))
                    return 1000;
                int value;
                if (!int.TryParse(o.ToString(), out value))
                    return 1000;

                return value - 10;
            }

            private void AddItemsToSprint(Data.ProjectDataSet dsItems, Data.ProjectDataSet.SprintRow sprint) {

                // do not want to modify the dsItems dataset, so copy it
                Data.ProjectDataSet dsSprintDefaultItems = new ProjectDataSet();
                dsSprintDefaultItems.EnforceConstraints = false;
                dsSprintDefaultItems.Merge(dsItems);

                // set the default items values
                short itemNumber = NextBacklogItemNumber;
                int businessValue = GetPreviousSprintLowestBusinessValue(sprint);
                foreach (Data.ProjectDataSet.BacklogItemRow r in dsSprintDefaultItems.BacklogItem.Rows) {
                    r.BacklogItemUId = Guid.NewGuid().ToString().ToLower();
                    r.BacklogItemNumber = itemNumber;
                    r.CreateDate = DateTime.Now;
                    r.ProjectUId = ProjectUId;
                    if (r.IsBusinessValueNull()) {
                        r.BusinessValue = businessValue;
                        businessValue = businessValue - 10;
                    }

                    r.Title = r.Title.Replace("$SPRINT_NUMBER$", sprint.SprintNumber.ToString());
                    r.Description = r.Description.Replace("$SPRINT_NUMBER$", sprint.SprintNumber.ToString());
                    itemNumber++;

                    if (r.GetBacklogItemHoursRows().Length == 0)
                        r.InsertZeroHourValues(sprint, ProjectDataSet.BacklogItemUnit.Select("Type <> " + +(short)TeamRoles.CLIENT_CONTACT + " AND ProjectUId='" + ProjectUId + "'"));

                }

                // adds them to the dataset
                ProjectDataSet.Merge(dsSprintDefaultItems.BacklogItem);
                ProjectDataSet.Merge(dsSprintDefaultItems.BacklogItemHours);

                // adds them to the VisibleBacklog table
                if (ProjectDataSet.IsConvertedToVisibleBacklog) {
                    foreach (Data.ProjectDataSet.BacklogItemRow r in dsSprintDefaultItems.BacklogItem.Rows)
                        ProjectDataSet.BacklogItem.AddAsVisibleBacklogItem(r, sprint);
                }
            }

            
                        
            public ProposalRow MarkedProposal { get; private set; }

            /// <summary>
            /// Updates the IsAtProposal Column for the VisibleBacklogItems of a given proposal.
            /// </summary>
            /// <param name="proposalUId">The proposal whos items will be marked</param>
            public void MarkVisibleBacklogItemsForProposal(string proposalUId) {

                ProposalRow proposal = ProjectDataSet.Proposal.FindByProposalUId(proposalUId);
                if (proposal == null)
                    throw new Exception("Could not mark proposal items. Proposal not found.");

                MarkedProposal = proposal;

                foreach (System.Data.DataRow item in ProjectDataSet.VisibleBacklogItem.Select("ProjectUId='" + ProjectUId + "'")) {
                    
                    ProposalItemRow proposalItem = ProjectDataSet.ProposalItem.FindByProposalUIdBacklogItemUIdSprintUIdBaseLine(
                        proposalUId,
                        item["BacklogItemUId"].ToString(),
                        item["SprintUId"].ToString(),
                        (int) item["BaseLine"]);

                    if (proposalItem == null)
                        item["IsAtProposal"] = false;
                    else
                        item["IsAtProposal"] = true;

                    
                }


                proposal.UpdateCalculatedCosts();
                proposal.UpdateSalePrice(proposal.UseDiscount);
                
            }


            /// <summary>
            /// Gets the next sprint number.
            /// </summary>
            public short NextSprintNumber {
                get {
                    short last = 0;
                    short.TryParse(ProjectDataSet.Sprint.Compute("MAX(SprintNumber)", "ProjectUId='" + ProjectUId + "'").ToString(), out last);
                    return (short) (last + 1);
                }
            }

            /// <summary>
            /// Gets the next business value for a new backlog item.
            /// </summary>
            public int NextBusinessValue {
                get {
                    if (ProjectDataSet.BacklogItem.Count == 0)
                        return 1000;

                    int last = 1010;
                    int.TryParse(ProjectDataSet.BacklogItem.Compute("MIN(BusinessValue)", "ProjectUId='" + ProjectUId + "'").ToString(), out last);
                    return (int)(last - 10);
                }
            }


            /// <summary>
            /// gets the next backlog item number.
            /// </summary>
            public short NextBacklogItemNumber {
                get {
                    short last = 0;
                    short.TryParse(ProjectDataSet.BacklogItem.Compute("MAX(BacklogItemNumber)", "ProjectUId='" + ProjectUId + "'").ToString(), out last);                    
                    return (short)(last + 1);
                }
            }

            /// <summary>
            /// Gets the project last sprint row.
            /// Returns null if the project has no sprints.
            /// </summary>
            public SprintRow LastSprint {
                get {

                    short lastSprintNumber = (short)(NextSprintNumber - 1);
                    if (lastSprintNumber < 0)
                        return null;

                    return FindSprintByNumber(lastSprintNumber);

                    //short lastSprintNumber = 0;
                    //object o = ProjectDataSet.Sprint.Compute("MAX(SprintNumber)", "ProjectUId='" + ProjectUId + "'");
                    //if (o == null || o == DBNull.Value)
                    //    return null;

                    //lastSprintNumber = (short)o;

                    //SprintRow[] lastSprint = (SprintRow[]) ProjectDataSet.Sprint.Select("ProjectUId='" + ProjectUId + "' and SprintNumber=" + lastSprintNumber);

                    //if (lastSprint.Length == 0)
                    //    return null;

                    //return lastSprint[0];

                }
            }

            public SprintRow FirstSprint {
                get {
                    return FindSprintByNumber(1);
                }
            }
            
            /// <summary>
            /// Gets the project current Sprint Row.
            /// Returns null id the project is over.
            /// Returns the first sprint if the project has not started yet.
            /// </summary>            
            public SprintRow CurrentSprint {
                get {

                    DateTime previousDate = EstimatedStartDate;
                    if (!IsStartDateNull())
                        previousDate = new DateTime(StartDate.Year, StartDate.Month, StartDate.Day);

                    DateTime today = DateTime.Now.Date;
                    SprintRow currentSprint = null;
                    foreach (SprintRow r in ProjectDataSet.Sprint.Select("ProjectUId='" + ProjectUId + "'", "SprintNumber")) {
                        if (r.RowState != System.Data.DataRowState.Deleted && r.RowState != System.Data.DataRowState.Detached) {

                            // if today is earlier than the project start date
                            //if (today < previousDate)
                            //    return r;

                            // if today is in the middle of the sprint
                            if (today >= previousDate && today <= r.ExpirationDate)
                                return r;

                            if (!r.IsExpirationDateNull())
                                previousDate = r.ExpirationDate;

                            currentSprint = r;
                        }
                    }

                    
                    // if the last sprint is over give them a null
                    return null;
                }                
            }


            /// <summary>
            /// Fill visible backlog items of this project.
            /// </summary>            
            internal void FillVisibleBacklog() {

                                                
                int actualBaseLine = Baseline; 

                // for each base line
                for (int bs = 0; bs <= actualBaseLine; bs++) {

                    // for each sprint of it
                    foreach (SprintRow sprint in GetSprintRows()) {

                        sprint.UpdateIsCurrentSprint();

                        // for each item 
                        foreach (BacklogItemRow item in GetBacklogItemRows()) {

                            if (item.IsBusinessValueNull())
                                item.BusinessValue = 0;

                            // if this item has hours at this sprint and baseline                            
                            if (item.GetBacklogItemHoursForSprint(sprint.SprintUId, bs).Length > 0) {
                                System.Data.DataRow visibleItem = ProjectDataSet.BacklogItem.AddAsVisibleBacklogItem(item, sprint, bs);
                                if (visibleItem != null) 
                                   visibleItem.AcceptChanges();
                            }

                            // it may happen that an item did not have any hours assign it to it at any sprint at any baseline
                            // so it wont appear at any sprint at any baseline
                            // i will add those at the current sprint and current base line
                            if (item.GetBacklogItemHoursRows().Length == 0 && bs == actualBaseLine && sprint==LastSprint) {
                                System.Data.DataRow visibleItem = ProjectDataSet.BacklogItem.AddAsVisibleBacklogItem(item, LastSprint, bs);
                                if (visibleItem != null) 
                                    visibleItem.AcceptChanges();
                            }

                            
                        }

                    }
                }

               

            }




            internal void UpdateIsPlanningLate() {
                if (EstimatedStartDate > DateTime.Today) {
                    this["IsPlanningLate"] = false;
                    return;
                }
            

                if (CurrentSprint != null) {
                    this["IsPlanningLate"] = (this.Baseline < CurrentSprint.SprintNumber);
                    return;
                }
                if (LastSprint != null) {
                    this["IsPlanningLate"] = (this.Baseline < LastSprint.SprintNumber);
                    return;
                }

                this["IsPlanningLate"] = false;

                
            }

            internal void UpdateTotalSize() {
                long size = 0;
                object o = ProjectDataSet.BacklogItem.Compute("SUM(Size)", "ProjectUId = '" + ProjectUId + "' AND Status <> 3");
                if (o != null && o != DBNull.Value)
                    size = (long)o;
                this.TotalSize = size;
            }



            internal void UpdateTotalHours() {
                double hours = 0;
                object o = ProjectDataSet.Sprint.Compute("SUM(TotalHours)", "ProjectUId = '" + ProjectUId + "'");
                if (o != null && o != DBNull.Value)
                    hours = (double)o;
                this["TotalHours"] = hours;
            }

            internal void UpdatePlannedVelocity() {                
                long size = 0;
                if (!IsTotalSizeNull())
                    size = this.TotalSize;
                double hours = 0;
                if (!IsNull("TotalHours"))
                    hours = (double)this["TotalHours"];
                if (hours != 0)
                    this["PlannedVelocity"] = size / hours;
                else
                    this["PlannedVelocity"] = 0;
            }


            /// <summary>
            /// Gets the sprint by its number.
            /// </summary>
            /// <param name="sprintNumber">The sprint number</param>
            /// <returns>The sprint row, or null if the project does not have the sprint</returns>
            public SprintRow FindSprintByNumber(short sprintNumber) {
                SprintRow[] sprints = (SprintRow[]) ProjectDataSet.Sprint.Select("SprintNumber=" + sprintNumber + " AND ProjectUId='" + ProjectUId + "'");
                if (sprints.Length > 0)
                    return sprints[0];

                return null;
            }


            public bool CanCreateANewBaseLine {
                get {

                    // if next base line greather than the number of sprints
                    if (NextBaseLine < 0)
                        return false;
                    
                    // if the project has not started or has ended
                    if (CurrentSprint == null) {

                        if (LastSprint == null)
                            return false;

                        if (Baseline == LastSprint.SprintNumber)
                            return false;
                        else
                            return true;                        
                    }

                    // if the baseline is gretaher the the current sprint
                    if (Baseline > CurrentSprint.SprintNumber)
                        return false;

                    return true;
                }
            }

            /// <summary>
            /// Gets the next baseline.
            /// In case of now more sprint to be planned return -1.
            /// </summary>
            public int NextBaseLine {
                get {

                    if (Baseline == GetSprintRows().Length)
                            return -1;

                    return Baseline + 1;

                    //if (CurrentSprint == null)
                    //    return -1;

                    //if (CurrentSprint.SprintNumber == Baseline) {
                    //    if (Baseline == GetSprintRows().Length)
                    //        return -1;

                    //    return Baseline + 1;
                    //}

                    //if (CurrentSprint.SprintNumber < Baseline) {
                    //    return -1;
                    //}

                    //return CurrentSprint.SprintNumber;
                }
            }

            /// <summary>
            /// Validates the project data for saving according its status.
            /// Throws an excpection in case of invalid data.
            /// </summary>            
            public void ValidateToSave() {

                switch (Status) {
                    
                    case (short)ProjectStatus.PROJECT_DONE:
                    case (short)ProjectStatus.PROJECT_MAINTANCE:
                    case (short)ProjectStatus.PROJECT_TESTFASE:
                    case (short)ProjectStatus.PROJECT_STARTED:
                        ValidateToSaveSummary();
                        ValidateToSavePayments();
                        ValidateToSaveRoles();
                        break;

                    case (short)ProjectStatus.PROPOSAL_APPROVED:
                        ValidateToSaveSummary();                        
                        ValidateToSavePayments();
                        break;

                    case (short)ProjectStatus.PROJECT_SUSPENDED:
                    case (short)ProjectStatus.PROJECT_CANCELED:
                    case (short)ProjectStatus.PROPOSAL_REJECTED:
                    case (short)ProjectStatus.PROPOSAL_WAITING:
                    case (short)ProjectStatus.PROPOSAL_CREATION:
                    case (short)ProjectStatus.CREATION:
                        ValidateToSaveSummary();
                        break;

                }

            }

            private void ValidateToSaveRoles() {


                return;

                // NOW THE CLIENT IS ONLY SENDING THE DATASET.GETCHANGES...
                // SO CAN NOT COMPARE THE NUMBER OF ROLES
                //foreach (Data.ProjectDataSet.BacklogItemUnitRow unit in ProjectDataSet.BacklogItemUnit.Select("Required=1 and ProjectUId='" + ProjectUId + "'")) {
                //    int roleCount = (int)ProjectDataSet.ProjectRole.Compute("count(UnitName)", "UnitName='" + unit.UnitName + "' and ProjectUId='" + ProjectUId + "'");
                //    if (roleCount == 0)
                //        throw new Exception("Role '" + unit.UnitName + "' need to be informed.");
                //}
            }

            private void ValidateToSaveSummary() {
                if (String.IsNullOrEmpty(ProjectName))
                    throw new Exception("Project Name need to be informed.");
                if (String.IsNullOrEmpty(ClientName))
                    throw new Exception("Client need to be informed.");
                if (String.IsNullOrEmpty(Description))
                    throw new Exception("Description need to be informed.");
                if (String.IsNullOrEmpty(Plataform))
                    throw new Exception("Project Plataform need to be informed.");
                if (String.IsNullOrEmpty(Model))
                    throw new Exception("Project Model need to be informed.");
                
                
              

            }

            private void ValidateToSavePayments() {

                return;
                /*
                if (IsPaymentProjectUIdNull()) {
                    foreach (Data.ProjectDataSet.ProposalRow prop in ProjectDataSet.Proposal.Select("ProjectUId='" + ProjectUId + "' AND Status=" + (short)ProposalStatus.PROPOSAL_APPROVED)) {
                        double salePrice = prop.SalePrice;
                        double paymentPrice = 0;
                        double.TryParse(ProjectDataSet.ProjectPayment.Compute("SUM(Value)", "ProposalUId='" + prop.ProposalUId + "'").ToString(), out paymentPrice);
                        if (paymentPrice < salePrice)
                            throw new Exception("Proposal '" + prop.ProposalName + "' Payments should be equal to its Sale Price");
                    }
                }*/

            }


            public bool IsReplanning { get; private set; }

            /// <summary>
            /// Creates a new baseline for the given project dataset.
            /// All planned itens are copied to the new baseline.
            /// </summary>
            /// <param name="project">The project Dataset</param>
            /// <returns>The project dataset with a new baseline</returns>
            public void CreateNewBaseLine() {
                
                if (!CanCreateANewBaseLine)
                    throw new Exception("Can not plan sprint. All Sprints are over, or the sprint still running.");

                IsReplanning = true;

                int nextBaseLine = NextBaseLine;

                ProjectDataSet.CleanUpVisibleBacklog();

                while (Baseline < nextBaseLine) {
                    CreateNewBaseLine(Baseline + 1);
                }

                
                ProjectDataSet.ConvertToVisibleBacklog();

                this["NextBaseLine"] = NextBaseLine;

                IsReplanning = false;
            }


            private void CreateNewBaseLine(int newBaseline) {


                // for each sprint starting of this baseline
                foreach (Data.ProjectDataSet.SprintRow sprint in ProjectDataSet.Sprint.Select("ProjectUId='" + ProjectUId + "' AND SprintNumber >= " + Baseline, "SprintNumber")) {

                    // for each backlog item                                                   
                    foreach (Data.ProjectDataSet.BacklogItemRow item in ProjectDataSet.BacklogItem.Select("ProjectUId='" + ProjectUId + "'", "BusinessValue DESC, BacklogitemNumber")) {

                        // get the hours planned at this baseline at this sprint for this item
                        Data.ProjectDataSet.BacklogItemHoursRow[] thisBaseLineHours = item.GetBacklogItemHoursForSprint(sprint.SprintUId);
                        bool itemIsAtSprint = (thisBaseLineHours.Length > 0);
                        
                        // if item has hours planned at this baseline at this sprint
                        if (itemIsAtSprint) {
                            
                            // should replan
                            bool shouldReplan = (sprint.SprintNumber > Baseline);

                            // automaticaly replan to the next sprint if the item was not finished
                            Data.ProjectDataSet.SprintRow newSprint = sprint;
                            if (sprint.SprintNumber <= Baseline &&
                                (item.Status.Equals((int)BacklogItemStatus.REQUIRED)
                                || item.Status.Equals((int)BacklogItemStatus.WORKING))) {
                                if (sprint.NextSprint != null) {
                                    newSprint = sprint.NextSprint;
                                    shouldReplan = true;
                                }
                            }
                             
                            if (shouldReplan) {
                                // if item still not have hours at this new baseline
                                if (item.GetBacklogItemHoursForSprint(sprint.SprintUId, newBaseline).Length == 0)
                                    foreach (Data.ProjectDataSet.BacklogItemHoursRow hour in thisBaseLineHours)
                                        ProjectDataSet.BacklogItemHours.AddBacklogItemHoursRow(
                                            Guid.NewGuid().ToString().ToLower(),
                                            item,
                                            item.ProjectUId,
                                            hour.UnitName,
                                            hour.Quantity,
                                            newSprint,
                                            newBaseline);
                            }                                                        
                        }
                    }
                }

                // set the risks previous probability
                foreach (Data.ProjectDataSet.RiskRow riskRow in GetRiskRows())
                    riskRow.PreviousBaselineProbability = riskRow.Probability;

                // now update the new baseline
                Baseline = newBaseline;

            }

            
        }

        

        /// <summary>
        /// Business functions for a backlogitem row.
        /// </summary>
        public partial class BacklogItemRow {

            /// <summary>
            /// Gets the ProjectDataSet of this project row.
            /// </summary>
            internal Data.ProjectDataSet ProjectDataSet {
                get {
                    Data.ProjectDataSet dsProject = this.Table.DataSet as Data.ProjectDataSet;
                    if (dsProject == null)
                        throw new Exception("Could not find project dataset from the row.");
                    return dsProject;
                }
            }


            public void SetSizeAccordingSizeType() {

                

                if (ProjectDataSet.SizeType == null)
                    return;
                
                if (IsSizeItemTypeNull()) {
                    Size = 0;
                    return;
                }

                Data.ProjectDataSet.SizeTypeRow sizeRow = ProjectDataSet.SizeType.FindBySizeItemType(SizeItemType);
                if (sizeRow == null)
                    return;

                

                Size = sizeRow.SizeValue;
                
            }

            /// <summary>
            /// Sets the backlogitem date according its status.
            /// </summary>
            public void SetFinishAccordingStatus() {

                // if the item was in the same state before                
                if (this.HasVersion(System.Data.DataRowVersion.Current) &&
                    this[tableBacklogItem.StatusColumn, System.Data.DataRowVersion.Current].Equals(
                    this[tableBacklogItem.StatusColumn, System.Data.DataRowVersion.Proposed]))
                    return;

                

                switch (Status) {
                    case (short)BacklogItemStatus.REQUIRED:
                        SetStartDateNull();
                        SetFinishDateNull();
                        SetVerifiedDateNull();
                        SetVerifiedByNull();
                        SetValidatedDateNull();
                        SetValidatedByNull();
                        SetCancelReasonNull();
                        break;
                    case (short)BacklogItemStatus.WORKING:
                        if (IsStartDateNull())
                            StartDate = DateTime.Now;
                        SetFinishDateNull();
                        SetCancelReasonNull();
                        break;
                    case (short)BacklogItemStatus.DONE:
                        if (IsStartDateNull())
                            StartDate = DateTime.Now;
                        FinishDate = DateTime.Now;
                        SetCancelReasonNull();
                        break;
                    case (short)BacklogItemStatus.CANCELED:
                        if (IsStartDateNull())
                            StartDate = DateTime.Now;
                        FinishDate = DateTime.Now;
                        CancelReason = (short)BacklogItemCancelReasons.UNKNOW;
                        break;
                }

            }


            /// <summary>
            /// Replans a backlogitem to another sprint.
            /// Basically it creates BacklogItemHours at the new sprint.
            /// </summary>
            /// <param name="SprintUId">The new sprint UId</param>
            public void ReplanToSprint(string sprintUId, System.Data.DataRowView newItem) {
                
                Data.ProjectDataSet.SprintRow sprint = ProjectDataSet.Sprint.FindBySprintUId(sprintUId);
                if (sprint == null)
                    throw new Exception("Could not replan item to sprint. Sprint was not found");

                Data.ProjectDataSet.ProjectRow project = ProjectDataSet.Project.FindByProjectUId(ProjectUId);
                if(project==null)
                    throw new Exception("Could not replan item to sprint. Project was not found");

                if(GetBacklogItemHoursForSprint(sprint.SprintUId).Length>0)
                    throw new Exception("Could not plan item to sprint. Item was already replanned to that sprint");
                
                newItem.Row.ItemArray = ProjectDataSet.BacklogItem.AsVisibleBacklogItem( this, sprint, project.Baseline).ItemArray;
                    
            }

            public void InsertZeroHourValues(String sprintUId) {

                Data.ProjectDataSet.SprintRow sprint = ProjectDataSet.Sprint.FindBySprintUId(sprintUId);
                if (sprint == null)
                    throw new Exception("Could not insert zero at this item units. Sprint was not found");

                InsertZeroHourValues(sprint, ProjectDataSet.BacklogItemUnit.Select("Type <> " + (short)TeamRoles.CLIENT_CONTACT));
            }

            public void InsertZeroHourValues(SprintRow sprint) {
                InsertZeroHourValues(sprint, ProjectDataSet.BacklogItemUnit.Select("Type <> " + (short)TeamRoles.CLIENT_CONTACT));
            }

            public void InsertZeroHourValues(SprintRow sprint, System.Data.DataRow[] units) {
                foreach (Data.ProjectDataSet.BacklogItemUnitRow unit in units) {                    
                    ProjectDataSet.BacklogItemHours.AddBacklogItemHoursRow(
                        Guid.NewGuid().ToString().ToLower(),
                        this,
                        this.ProjectUId,
                        unit.UnitName,
                        0,
                        sprint,
                        sprint.ProjectRow.Baseline);

                }
            }

            public double TotalHoursAtSprint(string sprintUId) {                
                string hourFilter = "ProjectUId='" + ProjectUId + "' AND BacklogItemUId='" + BacklogItemUId + "' AND SprintUId='" + sprintUId + "' AND BaseLine=" + ProjectRow.Baseline;
                object o = ProjectDataSet.BacklogItemHours.Compute("SUM(Quantity)", hourFilter);                
                double quantity;
                if (!double.TryParse(o.ToString(), out quantity))
                    quantity = 0;

                return quantity;
            }


            /// <summary>
            /// Gets the project hours for a given backlogitem at a given baseline.
            /// </summary>                    
            /// <param name="sprintUId">The sprint UId</param>
            /// <param name="baseline">The baseline</param>
            /// <returns>An array of backlog item hours row</returns>
            public ProjectDataSet.BacklogItemHoursRow[] GetBacklogItemHoursForSprint(string sprintUId, int baseline) {                
                string hourFilter = "ProjectUId='" + ProjectUId + "' AND BacklogItemUId='" + BacklogItemUId + "' AND SprintUId='" + sprintUId + "' AND BaseLine=" + baseline;
                return (ProjectDataSet.BacklogItemHoursRow[])ProjectDataSet.BacklogItemHours.Select(hourFilter);
            }

            /// <summary>
            /// Gets the project hours for a given backlogitem at the current baseline.
            /// </summary>                    
            /// <param name="sprintUId">The sprint UId</param>            
            /// <returns>An array of backlog item hours row</returns>
            public ProjectDataSet.BacklogItemHoursRow[] GetBacklogItemHoursForSprint(string sprintUId) {
                Data.ProjectDataSet.ProjectRow project = ProjectDataSet.Project.FindByProjectUId(ProjectUId);
                return GetBacklogItemHoursForSprint(sprintUId, project.Baseline);
            }

            public bool HasVisibleItemAtSprint(string sprintUId) {
                return (GetBacklogItemHoursForSprint(sprintUId).Length != 0);
            }

            /// <summary>
            /// Gets the last Plan for this item (the higest baselien that it was planned).
            /// </summary>
            public int LastPlanBaseline {
                get {
                    // firts figuret out the last PLAN for this item
                    string hourFilter = "ProjectUId='" + ProjectUId + "' AND BacklogItemUId='" + BacklogItemUId + "'";
                    object o = ProjectDataSet.BacklogItemHours.Compute("MAX(BaseLine)", hourFilter);
                    int baseline;
                    if (!int.TryParse(o.ToString(), out baseline))
                        return -1;
                    return baseline;
                }
            }
        

            /// <summary>
            /// Gets the sprint this item is planned to be delivery or has been deliveried.
            /// </summary>
            public SprintRow DeliverySprint {
                get {
                    string hourFilter = "ProjectUId='" + ProjectUId + "' AND BacklogItemUId='" + BacklogItemUId + "' AND BaseLine=" + LastPlanBaseline;
                    ProjectDataSet.BacklogItemHoursRow[] hours = 
                        (ProjectDataSet.BacklogItemHoursRow[])ProjectDataSet.BacklogItemHours.Select(hourFilter);
                    if (hours.Length == 0)
                        return null;
                    return hours[0].SprintRow;
                }
            }
     

        }

        /// <summary>
        /// Business functions for a backlogitemHours datatable.
        /// </summary>
        public partial class BacklogItemHoursDataTable {

            /// <summary>
            /// Gets a backlogitemhoour row based at its unique values.
            /// </summary>
            /// <param name="backlogitemUId">The backlogItemUId</param>
            /// <param name="sprintUId">The sprintUId</param>
            /// <param name="unitName">The unitName</param>
            /// <param name="baseline">The baseline</param>
            /// <returns>The unique backlogitemhour row with this values, null if it does not exist</returns>
            public BacklogItemHoursRow FindByUniqueValues(string backlogitemUId, string sprintUId, string unitName, int baseline) {
                BacklogItemHoursRow[] hours = (BacklogItemHoursRow[]) Select("backlogitemUId='" + backlogitemUId + "' and SprintUId='" + sprintUId + "' and UnitName='" + unitName + "' and Baseline=" + baseline);
                if (hours.Length == 0)
                    return null;
                return hours[0];
            }

                        

        }


        public partial class BacklogItemDataTable {

            public System.Data.DataRow AsVisibleBacklogItem(Data.ProjectDataSet.BacklogItemRow item, SprintRow sprint) {
                return AsVisibleBacklogItem(item, sprint, sprint.ProjectRow.Baseline);
            }

            public System.Data.DataRow AsVisibleBacklogItem(Data.ProjectDataSet.BacklogItemRow item, string sprintUId, int baseline) {
                return AsVisibleBacklogItem(item, ProjectDataSet.Sprint.FindBySprintUId(sprintUId), baseline);
            }

            internal System.Data.DataRow AddAsVisibleBacklogItem(Data.ProjectDataSet.BacklogItemRow item, SprintRow sprint) {
                return AddAsVisibleBacklogItem(item, sprint, sprint.ProjectRow.Baseline);
            }

            /// <summary>
            /// Adds a visible backlogitem from this item at a given sprint and baseline.
            /// </summary>            
            /// <param name="sprint">The sprint of the visible backlog item</param>
            /// <param name="baseline">The baseline of the visible backlog item</param>
            /// <returns>The added row</returns>
            internal System.Data.DataRow AddAsVisibleBacklogItem(Data.ProjectDataSet.BacklogItemRow item, SprintRow sprint, int baseline) {
                // adds the item
                System.Data.DataRow visibleItem = this.AsVisibleBacklogItem(item, sprint, baseline);

                if (visibleItem != null) 
                    ProjectDataSet.VisibleBacklogItem.Rows.Add(visibleItem);                
                
                return visibleItem;

            }

            public System.Data.DataRow AsVisibleBacklogItem(Data.ProjectDataSet.BacklogItemRow item, SprintRow sprint, int baseline) {

                // firsts gets the hours for this backlog item at this sprint, at this baseline
                // no hours means that there is noe visible backlog item to be added
                BacklogItemHoursRow[] hours = item.GetBacklogItemHoursForSprint(sprint.SprintUId, baseline);
                //if (hours.Length == 0)
                //    return null;

                // adds the item
                System.Data.DataRow newRow = ProjectDataSet.VisibleBacklogItem.NewRow();


                newRow.ItemArray = item.ItemArray;

                ProjectDataSet.isReflectingVisibleChanges = true;

                Data.ProjectDataSet.ProjectRow project = ProjectDataSet.Project.FindByProjectUId(item.ProjectUId);

                // sets it basic values
                newRow["SprintUId"] = sprint.SprintUId;
                newRow["SprintNumber"] = sprint.SprintNumber;
                newRow["BaseLine"] = baseline;
                newRow["IsSprintOver"] = sprint.ExpirationDate.Date < DateTime.Today;
                newRow["IsPlanOver"] = (baseline < project.Baseline);
                newRow["IsVisible"] = (baseline == sprint.ProjectRow.Baseline || baseline == sprint.SprintNumber);


                // sets the hours values
                foreach (BacklogItemHoursRow h in hours) {
                    string unitColumnName = ProjectDataSet.GetVisibleUnitColumnName(h.UnitName);
                    if (ProjectDataSet.VisibleBacklogItem.Columns.Contains(unitColumnName))
                        newRow[unitColumnName] = h.Quantity;
                }

                ProjectDataSet.isReflectingVisibleChanges = false;
                return newRow;
            }


            /// <summary>
            /// Every time one column change at the backlog, updates its depedency columns.
            /// </summary>
            /// <param name="e"></param>
            protected override void OnColumnChanged(System.Data.DataColumnChangeEventArgs e) {
                base.OnColumnChanged(e);

                // If status was changed, updates start and finish date
                if (e.Column == StatusColumn) {
                    BacklogItemRow item = e.Row as BacklogItemRow;
                    item.SetFinishAccordingStatus();                    
                }

                if(e.Column == SizeItemTypeColumn) {
                    BacklogItemRow item = e.Row as BacklogItemRow;
                    item.SetSizeAccordingSizeType();
                }

            }


            /// <summary>
            /// Gets the ProjectDataSet of this project row.
            /// </summary>
            internal Data.ProjectDataSet ProjectDataSet {
                get {
                    Data.ProjectDataSet dsProject = DataSet as Data.ProjectDataSet;
                    if (dsProject == null)
                        throw new Exception("Could not find project dataset from the table.");
                    return dsProject;
                }
            }


        }


        public partial class RiskDataTable {

            /// <summary>
            /// Gets the ProjectDataSet of this project row.
            /// </summary>
            internal Data.ProjectDataSet ProjectDataSet {
                get {
                    Data.ProjectDataSet dsProject = DataSet as Data.ProjectDataSet;
                    if (dsProject == null)
                        throw new Exception("Could not find project dataset from the table.");
                    return dsProject;
                }
            }


            public override void EndInit() {
                base.EndInit();                
                TableNewRow += new System.Data.DataTableNewRowEventHandler(RiskDataTable_TableNewRow);
            }

            void RiskDataTable_TableNewRow(object sender, System.Data.DataTableNewRowEventArgs e) {
                SetDefaultValues((RiskRow)e.Row);   
            }

            public void SetDefaultValues(RiskRow riskRow) {
                riskRow.RiskUId = Guid.NewGuid().ToString().ToLower();                
                riskRow.ProjectUId = ProjectDataSet.Project[0].ProjectUId;
                riskRow.CreateDate = DateTime.Today;
            }



        }


        /// <summary>
        /// Business functions for a Sprint row.
        /// </summary>
        public partial class SprintRow {

            /// <summary>
            /// Gets the ProjectDataSet of this project row.
            /// </summary>
            internal Data.ProjectDataSet ProjectDataSet {
                get {
                    Data.ProjectDataSet dsProject = this.Table.DataSet as Data.ProjectDataSet;
                    if (dsProject == null)
                        throw new Exception("Could not find project dataste from the row.");
                    return dsProject;
                }
            }
           
            internal void UpdateIsPlanOver() {
                if (RowState.Equals(System.Data.DataRowState.Deleted))
                    return;
                if (ProjectRow != null)
                    this["IsPlanOver"] = (SprintNumber < ProjectRow.Baseline);
                else
                    this["IsPlanOver"] = true;

            }

            public bool IsLastSprint {
                get {                    
                    if (ProjectRow != null)
                        return (ProjectRow.GetSprintRows().Length == SprintNumber);
                    else
                        return false;
                }
            }

            internal void UpdateCodeRevision() {
                if (System.Data.DataRowState.Detached.Equals(RowState) || System.Data.DataRowState.Deleted.Equals(RowState))
                    return;
                Data.ProjectDataSet.SprintCodeVersionRow codeRevision = ProjectDataSet.SprintCodeVersion.FindBySprintUId(SprintUId);
                if (codeRevision != null)
                    this["CodeVersion"] = codeRevision.CodeVersion;
                else
                    this["CodeVersion"] = 0;

            }
        

            internal void UpdateIsLastSprint() {
                if(System.Data.DataRowState.Detached.Equals(RowState) || System.Data.DataRowState.Deleted.Equals(RowState))
                    return;

                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return;

                this["IsLastSprint"] = IsLastSprint;
                
                if (IsLastSprint)
                    ProjectRow.EstimatedEndDate = ExpirationDate;
            }

            internal void UpdateIsCurrentSprint() {
                if(System.Data.DataRowState.Detached.Equals(RowState) || System.Data.DataRowState.Deleted.Equals(RowState))
                    return;
                if (this.ProjectRow == null)
                    return;
                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return;
                this["IsCurrentSprint"] = (this == this.ProjectRow.CurrentSprint);               
            }

            internal void UpdateTotalSize() {
                if (RowState.Equals(System.Data.DataRowState.Deleted))
                    return;
                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return;
                long totalSize = 0;
                object o = ProjectDataSet.VisibleBacklogItem.Compute("SUM(Size)", "SprintUId='" + SprintUId + "'  and IsVisible=1 AND Status<>3");
                if (o != null && o != DBNull.Value)
                    totalSize = (long) o;
                this["TotalSize"] = totalSize;
           
            }

            internal void UpdateTotalHours() {

                if (RowState.Equals(System.Data.DataRowState.Deleted))
                    return;

                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return;

                double totalHours = 0;

                foreach (System.Data.DataColumn c in ProjectDataSet.VisibleBacklogItem.Columns) {
                    if (c.ColumnName.StartsWith("unit")) {
                        object o = ProjectDataSet.VisibleBacklogItem.Compute("SUM(" + c.ColumnName + ")", "SprintUId='" + SprintUId + "' and IsVisible=1 and Status<>3");
                        if (o != null && o != DBNull.Value)
                            totalHours = totalHours + (double)o;
                    }
                }
                this["TotalHours"] = totalHours;
            }

            internal void UpdatePlannedVelocity() {

                if (RowState.Equals(System.Data.DataRowState.Deleted))
                    return;

                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return;
                
                long size = 0;
                if (!IsNull("TotalSize"))
                    size = (long)this["TotalSize"];
                double hours = 0;
                if (!IsNull("TotalHours"))
                    hours = (double)this["TotalHours"];
                if (hours != 0)
                    this["PlannedVelocity"] = size / hours;
                else
                    this["PlannedVelocity"] = 0;
            }

            internal void UpdateWorkDayCount() {
                if (RowState.Equals(System.Data.DataRowState.Deleted))
                    return;

                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return;

                this["WorkDayCount"] = WorkDayCount;
            }

            internal void UpdateWorkDayLeft() {
                if (RowState.Equals(System.Data.DataRowState.Deleted))
                    return;

                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return;

                this["WorkDayLeft"] = WorkDayLeft;
            }

            internal void UpdateNumberOfMembersNeeded() {
                if (RowState.Equals(System.Data.DataRowState.Deleted))
                    return;

                if (!ProjectDataSet.IsConvertedToVisibleBacklog)
                    return;
                
                double hours = 0;
                if (!IsNull("TotalHours"))
                    hours = (double)this["TotalHours"];

                this["NumberOfMembersNeeded"] = CalcNumberOfMembersNeedForDoItIn(hours);

                
            }

            public DateTime StartDate {
                get {
                    if (SprintNumber == 1) {
                        return ProjectRow.EstimatedStartDate;                        
                    }
                    SprintRow previousSprint = ProjectRow.FindSprintByNumber((short)(SprintNumber - 1));
                    return previousSprint.ExpirationDate.AddDays(1);
                }
            }

            /// <summary>
            /// Gets the number of members needed to implement this sprint in a given amount of hours.
            /// </summary>
            /// <param name="hours"></param>
            /// <returns></returns>
            public double CalcNumberOfMembersNeedForDoItIn(double hours) {                
                if (hours == 0)
                    return 0;
                
                return hours/WorkDayCount/8;
            }


            public int WorkDayCount {
                get {
                    return CalcWorkDayCount(StartDate, ExpirationDate); 
                }
            }

            public int WorkDayLeft {
                get {
                    return CalcWorkDayCount(DateTime.Today, ExpirationDate);
                }
            }


            public void ValidadeExpirationDate(System.Data.DataColumnChangeEventArgs e) {

                if (System.Data.DataRowState.Detached.Equals(RowState) || System.Data.DataRowState.Deleted.Equals(RowState))
                    return;

                DateTime newDate = (DateTime) e.ProposedValue;
                               

                if (newDate < StartDate)
                    throw new Exception("Sprint Expiration Date can not be earlier than its start date.");

                if (NextSprint != null) {
                    if(newDate > NextSprint.ExpirationDate)
                        throw new Exception("Sprint Expiration Date can not be after next sprint expiration date.");
                }


                if (IsLastSprint)
                    ProjectRow.EstimatedEndDate = newDate;

                

            }

            public SprintRow NextSprint {
                get {
                    if (IsLastSprint)
                        return null;
                    SprintRow nextSprint = ProjectRow.FindSprintByNumber((short)(SprintNumber + 1));
                    return nextSprint;
                }
            }

        }

        /// <summary>
        /// Business functions for a Sprint row.
        /// </summary>
        public partial class ProposalRow {

            /// <summary>
            /// Gets the ProjectDataSet of this project row.
            /// </summary>
            internal Data.ProjectDataSet ProjectDataSet {
                get {
                    Data.ProjectDataSet dsProject = this.Table.DataSet as Data.ProjectDataSet;
                    if (dsProject == null)
                        throw new Exception("Could not find project dataset from the row.");
                    return dsProject;
                }
            }


            public void InsertOrfansBacklogItems() {

                // for each visible backlogitem of this project at the current baseline
                //foreach(System.Data.DataRow item in ProjectDataSet.VisibleBacklogItem.Select("ProjectUId='" + ProjectRow.ProjectUId + "' and BaseLine=" + ProjectRow.Baseline) {                    
                //}

            }
            

            public void UpdateCalculatedCosts() {
                UpdateCalculatedBacklogCosts();
                UpdateCalculatedFixedCost();
                UpdateCalculatedTotalPrice(Discount);                
                UpdateHoursAtProposal();
            }

            private void UpdateCalculatedBacklogCosts() {
                decimal totalCost = 0;
                decimal totalPrice = 0;
                // for each item of this proposal
                foreach (Data.ProjectDataSet.ProposalItemRow propItem in GetProposalItemRows()) {
                    decimal cost = 0;
                    decimal price = 0;
                    double hours = 0;
                    ProjectDataSet.CalcItemCosts(propItem.BacklogItemUId, propItem.SprintUId, propItem.BaseLine, out cost, out price, out hours);                    
                    totalCost = totalCost + cost;
                    totalPrice = totalPrice + price;
                }
                this["CalculatedBacklogPrice"] = totalPrice;
                this["CalculatedBacklogCost"] = totalCost;

            }

            public void UpdateSalePrice() {
                UpdateSalePrice(UseDiscount);
            }

            public void UpdateSalePrice(bool useDiscount) {
                if (useDiscount) {
                    this.SalePrice = (decimal)this["CalculatedTotalPrice"];                    
                }
            }

            private void UpdateCalculatedFixedCost() {                
                object cost = ProjectDataSet.ProposalFixedCostItem.Compute("SUM(ItemValue)", "ProposalUId='" + ProposalUId + "' AND Payable=1");
                if (cost != null && !cost.Equals(DBNull.Value))
                    this["CalculatedFixedCost"] = cost;
                else
                    this["CalculatedFixedCost"] = 0;
               
            }


            public void UpdateCalculatedTotalPrice(decimal discount) {
                decimal backlogPrice = (decimal)this["CalculatedBacklogPrice"];
                decimal fixedCost = (decimal)this["CalculatedFixedCost"];
                this["CalculatedTotalPrice"] = (backlogPrice + fixedCost) * ((100-discount)/100);             
            }

            private void UpdateHoursAtProposal() {
                if (ProjectDataSet.VisibleBacklogItem == null)
                    return;
                foreach (BacklogItemUnitRow unit in ProjectDataSet.BacklogItemUnit.Select("Type <> "  + (short)TeamRoles.CLIENT_CONTACT + " and ProjectUId='" + ProjectUId + "'")) {
                    double hoursAtProposal = 0;
                    object o = ProjectDataSet.VisibleBacklogItem.Compute("SUM(" + ProjectDataSet.GetVisibleUnitColumnName(unit.UnitName) + ")", "ProjectUId='" + ProjectUId + "' and IsAtProposal=1");
                    if (o != null)
                        double.TryParse(o.ToString(), out hoursAtProposal);

                    unit["HoursAtProposal"] = hoursAtProposal;
                          
                }

            }



            
            

        }


        

    }

}
